package cn.thoughtworks.school.services;

import cn.thoughtworks.school.entities.Stack;
import cn.thoughtworks.school.entities.Tag;
import cn.thoughtworks.school.entities.User;
import cn.thoughtworks.school.entities.UserQuizGroup;
import cn.thoughtworks.school.entities.dto.AssignmentQuizData;
import cn.thoughtworks.school.repositories.StackRepository;
import cn.thoughtworks.school.repositories.TagRepository;
import cn.thoughtworks.school.repositories.UserQuizGroupRepository;
import cn.thoughtworks.school.requestParams.YmlConvertQuiz;
import cn.thoughtworks.school.utils.ZipUtil;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class QuizService {

    @Autowired
    private UserQuizGroupRepository userQuizGroupRepository;
    @Autowired
    private UserCenterService userCenterService;
    @Autowired
    private SubjectiveQuizService subjectiveQuizService;
    @Autowired
    private BasicQuizService basicQuizService;
    @Autowired
    private HomeworkQuizService homeworkQuizService;
    @Autowired
    private SimpleCodingQuizService simpleCodingQuizService;
    @Autowired
    private OnlineLanguageQuizService onlineLanguageQuizService;
    @Autowired
    private LogicQuizService logicQuizService;
    @Autowired
    private OnlineCodingQuizService onlineCodingQuizService;
    @Autowired
    private StackRepository stackRepository;
    @Autowired
    private TagRepository tagRepository;
    @Autowired
    private SurveyQuizService surveyQuizService;

    public List<Long> getGroupIdsByUserId(Long userId) {
        Long organizationId = userCenterService.getUserCurrentOrganizationId(userId);
        List<UserQuizGroup> userQuizGroupList = userQuizGroupRepository.findByUserIdAndOrganizationId(userId, organizationId);
        return userQuizGroupList.stream().map(UserQuizGroup::getQuizGroupId).collect(Collectors.toList());
    }

    public List<Predicate> getDefaultPredicates(Long organizationId, Long id, Long userId, String description, List<Long> quizIds, Root root, CriteriaBuilder criteriaBuilder) {
        List<Predicate> predicates = new ArrayList<>();
        predicates.add(criteriaBuilder.equal(root.get("organizationId").as(Long.class), organizationId));
        predicates.add(criteriaBuilder.equal(root.get("isAvailable").as(Boolean.class), true));

        if (Objects.nonNull(id)) {
            predicates.add(criteriaBuilder.equal(root.get("id").as(Long.class), id));
        }
        if (Objects.nonNull(userId)) {
            predicates.add(criteriaBuilder.equal(root.get("makerId").as(Long.class), userId));
        }
        if (Objects.nonNull(description)) {
            predicates.add(criteriaBuilder.like(root.get("description").as(String.class), "%" + description + "%"));
        }
        if (!quizIds.isEmpty()) {
            predicates.add(root.<Long>get("id").in(quizIds));
        }
        return predicates;
    }

    public List<AssignmentQuizData> copyQuizzes(List<AssignmentQuizData> assignmentQuizData) {
        List<AssignmentQuizData> result = new ArrayList<>();
        List<AssignmentQuizData> subjectiveQuizzes = filterByType(assignmentQuizData, "SUBJECTIVE_QUIZ");
        result.addAll(subjectiveQuizService.copy(subjectiveQuizzes));

        List<AssignmentQuizData> homeworkQuizzes = filterByType(assignmentQuizData, "HOMEWORK_QUIZ");
        result.addAll(homeworkQuizService.copy(homeworkQuizzes));

        List<AssignmentQuizData> basicQuizzes = filterByType(assignmentQuizData, "BASIC_QUIZ");
        result.addAll(basicQuizService.copy(basicQuizzes));

        List<AssignmentQuizData> onlineLanguageQuizzes = filterByType(assignmentQuizData, "ONLINE_LANGUAGE_QUIZ");
        result.addAll(onlineLanguageQuizService.copy(onlineLanguageQuizzes));

        List<AssignmentQuizData> logicQuizzes = filterByType(assignmentQuizData, "LOGIC_QUIZ");
        result.addAll(logicQuizService.copy(logicQuizzes));

        List<AssignmentQuizData> onlineCodingQuizzes = filterByType(assignmentQuizData, "ONLINE_CODING_QUIZ");
        result.addAll(onlineCodingQuizService.copy(onlineCodingQuizzes));

        List<AssignmentQuizData> simpleCodingQuizzes = filterByType(assignmentQuizData, "SIMPLE_CODING_QUIZ");
        result.addAll(simpleCodingQuizService.copy(simpleCodingQuizzes));

        List<AssignmentQuizData> surveyQuizzes = filterByType(assignmentQuizData, "SURVEY_QUIZ");
        result.addAll(surveyQuizService.copy(surveyQuizzes));

        return result;
    }

    private List<AssignmentQuizData> filterByType(List<AssignmentQuizData> assignmentQuizData, String type) {
        return assignmentQuizData.stream().filter(assignmentQuiz -> type.equals(assignmentQuiz.getType()))
            .collect(Collectors.toList());
    }

    public Long copyStack(Long organizationId, Long stackId, Long creatorId) {
        Stack stack = stackRepository.findById(stackId).get();
        Optional<Stack> optionalStack = stackRepository.findByTitleAndOrganizationId(stack.getTitle(), organizationId);
        if (!optionalStack.isPresent()) {
            stack = new Stack(stack.getDescription(), stack.getImage(), creatorId, stack.getTitle(), organizationId);
            return stackRepository.save(stack).getId();
        }
        return optionalStack.get().getId();
    }

    public Set<Tag> copyTags(Long organizationId, Set<Tag> tags, Long creatorId) {
        Set<Tag> result = new HashSet<>();
        tags.forEach(tag ->
            {
                Tag foundTag = tagRepository.findFirstByNameAndOrganizationId(tag.getName(), organizationId)
                    .orElse(new Tag(tag.getName(), creatorId, organizationId));
                result.add(foundTag);
            }
        );
        return result;
    }

    @Transactional
    public void ymlImport(MultipartFile multipartFile, User current) throws IOException {
        File file = convertToFile(multipartFile);
        YmlConvertQuiz converter = ZipUtil.readYml(file);
        basicQuizService.convertUpdateBasicQuizzes(converter, current);
        surveyQuizService.convertUpdateSurveyQuizzes(converter, current);
        deleteTempSpace();
    }

    private File convertToFile(MultipartFile multipartFile) throws IOException {
        File file = new File(getTempSpacePath() + "/" + multipartFile.getOriginalFilename());
        multipartFile.transferTo(file);
        return file;
    }

    private String getTempSpacePath() {
        File fileTemp = new File(".");
        String temp = fileTemp.getAbsolutePath() + "/backend/src/main/resources/static/quizzes";
        File tempDir = new File(temp);
        if (!tempDir.exists()) {
            tempDir.mkdirs();
        }
        return temp;
    }

    private void deleteTempSpace() throws IOException {
        String tempSpacePath = getTempSpacePath();
        FileUtils.deleteDirectory(new File(tempSpacePath));
    }
}
